import 'package:look_net_ip_util/look_net_ip_utils.dart';
import 'package:test/test.dart';

import 'package:faker/faker.dart';

void main() {
  var ipUtils = IpUtils();

  var ipv4List = [
    IpUtils.ipv4MinString,
    IpUtils.ipv4MaxString,
    '192.168.01.001',
    '000.000.000.000',
    '0.00.000.000'
  ];

  var ipv4ErrorList = [
    '000.000.000.0001',
    '256.255.255.255',
    '192.168.01.01.0',
    '138.198.1.',
    '.98.198.138'
  ];

  var ipv4ListAny =
      ipUtils.generateRandomIpv4List(10000, outputMode: LeadingZerosMode.any);
  var ipv4ListIncluded = ipUtils.generateRandomIpv4List(10000,
      outputMode: LeadingZerosMode.included);
  var ipv4ListIncludedCompletely = ipUtils.generateRandomIpv4List(10000,
      outputMode: LeadingZerosMode.includedCompletely);
  var ipv4ListExcluded = ipUtils.generateRandomIpv4List(10000,
      outputMode: LeadingZerosMode.excluded);

  group('isIpv4 Test', () {
    var isIpv4 = ipUtils.isIpv4;

    test('Test isIpv4 any', () {
      // any
      for (var i = 0; i < ipv4List.length; i++) {
        expect(isIpv4(ipv4List[i], inputMode: LeadingZerosMode.any), true);
      }
      for (var i = 0; i < ipv4ListAny.length; i++) {
        expect(isIpv4(ipv4ListAny[i], inputMode: LeadingZerosMode.any), true);
      }
    });

    test('Test isIpv4 included', () {
      // included
      expect(isIpv4(ipv4List[0], inputMode: LeadingZerosMode.included), false);
      expect(isIpv4(ipv4List[1], inputMode: LeadingZerosMode.included), true);
      expect(isIpv4(ipv4List[2], inputMode: LeadingZerosMode.included), true);
      expect(isIpv4(ipv4List[3], inputMode: LeadingZerosMode.included), true);
      expect(isIpv4(ipv4List[4], inputMode: LeadingZerosMode.included), false);
      for (var i = 0; i < ipv4ListIncluded.length; i++) {
        expect(
            isIpv4(ipv4ListIncluded[i], inputMode: LeadingZerosMode.included),
            true);
      }
    });

    test('Test isIpv4 includedCompletely', () {
      // includedCompletely
      expect(
          isIpv4(ipv4List[0], inputMode: LeadingZerosMode.includedCompletely),
          false);
      expect(
          isIpv4(ipv4List[1], inputMode: LeadingZerosMode.includedCompletely),
          true);
      expect(
          isIpv4(ipv4List[2], inputMode: LeadingZerosMode.includedCompletely),
          false);
      expect(
          isIpv4(ipv4List[3], inputMode: LeadingZerosMode.includedCompletely),
          true);
      expect(
          isIpv4(ipv4List[4], inputMode: LeadingZerosMode.includedCompletely),
          false);
      for (var i = 0; i < ipv4ListIncludedCompletely.length; i++) {
        expect(
            isIpv4(ipv4ListIncludedCompletely[i],
                inputMode: LeadingZerosMode.includedCompletely),
            true);
      }
    });

    test('Test isIpv4 excluded', () {
      // excluded
      expect(isIpv4(ipv4List[0], inputMode: LeadingZerosMode.excluded), true);
      expect(isIpv4(ipv4List[1], inputMode: LeadingZerosMode.excluded), true);
      expect(isIpv4(ipv4List[2], inputMode: LeadingZerosMode.excluded), false);
      expect(isIpv4(ipv4List[3], inputMode: LeadingZerosMode.excluded), false);
      expect(isIpv4(ipv4List[4], inputMode: LeadingZerosMode.excluded), false);

      for (var i = 0; i < ipv4ListExcluded.length; i++) {
        expect(
            isIpv4(ipv4ListExcluded[i], inputMode: LeadingZerosMode.excluded),
            true);
      }
    });

    test('Test isIpv4 error', () {
      for (var i = 0; i < ipv4ErrorList.length; i++) {
        expect(
            isIpv4(ipv4ErrorList[i], inputMode: LeadingZerosMode.any), false);
        expect(isIpv4(ipv4ErrorList[i], inputMode: LeadingZerosMode.included),
            false);
        expect(
            isIpv4(ipv4ErrorList[i],
                inputMode: LeadingZerosMode.includedCompletely),
            false);
        expect(isIpv4(ipv4ErrorList[i], inputMode: LeadingZerosMode.excluded),
            false);
      }
    });
  });

  group('isIpv4Parts Test', () {
    var isIpv4Parts = ipUtils.isIpv4Segments;

    test('Test isIpv4Parts any', () {
      // any
      for (var i = 0; i < ipv4List.length; i++) {
        var parts = ipv4List[i].split('.');
        expect(isIpv4Parts(parts, inputMode: LeadingZerosMode.any), true);
      }
      for (var i = 0; i < ipv4ListAny.length; i++) {
        var parts = ipv4ListAny[i].split('.');
        expect(isIpv4Parts(parts, inputMode: LeadingZerosMode.any), true);
      }
    });

    test('Test isIpv4Parts included', () {
      // included
      var parts0 = ipv4List[0].split('.');
      var parts1 = ipv4List[1].split('.');
      var parts2 = ipv4List[2].split('.');
      var parts3 = ipv4List[3].split('.');
      var parts4 = ipv4List[4].split('.');

      expect(isIpv4Parts(parts0, inputMode: LeadingZerosMode.included), false);
      expect(isIpv4Parts(parts1, inputMode: LeadingZerosMode.included), true);
      expect(isIpv4Parts(parts2, inputMode: LeadingZerosMode.included), true);
      expect(isIpv4Parts(parts3, inputMode: LeadingZerosMode.included), true);
      expect(isIpv4Parts(parts4, inputMode: LeadingZerosMode.included), false);

      for (var i = 0; i < ipv4ListIncluded.length; i++) {
        var parts = ipv4ListIncluded[i].split('.');
        expect(isIpv4Parts(parts, inputMode: LeadingZerosMode.included), true);
      }
    });

    test('Test isIpv4Parts includedCompletely', () {
      // includedCompletely
      var parts0 = ipv4List[0].split('.');
      var parts1 = ipv4List[1].split('.');
      var parts2 = ipv4List[2].split('.');
      var parts3 = ipv4List[3].split('.');
      var parts4 = ipv4List[4].split('.');

      expect(
          isIpv4Parts(parts0, inputMode: LeadingZerosMode.includedCompletely),
          false);
      expect(
          isIpv4Parts(parts1, inputMode: LeadingZerosMode.includedCompletely),
          true);
      expect(
          isIpv4Parts(parts2, inputMode: LeadingZerosMode.includedCompletely),
          false);
      expect(
          isIpv4Parts(parts3, inputMode: LeadingZerosMode.includedCompletely),
          true);
      expect(
          isIpv4Parts(parts4, inputMode: LeadingZerosMode.includedCompletely),
          false);

      for (var i = 0; i < ipv4ListIncludedCompletely.length; i++) {
        var parts = ipv4ListIncludedCompletely[i].split('.');
        expect(
            isIpv4Parts(parts, inputMode: LeadingZerosMode.includedCompletely),
            true);
      }
    });

    test('Test isIpv4Parts excluded', () {
      // excluded
      var parts0 = ipv4List[0].split('.');
      var parts1 = ipv4List[1].split('.');
      var parts2 = ipv4List[2].split('.');
      var parts3 = ipv4List[3].split('.');
      var parts4 = ipv4List[4].split('.');

      expect(isIpv4Parts(parts0, inputMode: LeadingZerosMode.excluded), true);
      expect(isIpv4Parts(parts1, inputMode: LeadingZerosMode.excluded), true);
      expect(isIpv4Parts(parts2, inputMode: LeadingZerosMode.excluded), false);
      expect(isIpv4Parts(parts3, inputMode: LeadingZerosMode.excluded), false);
      expect(isIpv4Parts(parts4, inputMode: LeadingZerosMode.excluded), false);

      for (var i = 0; i < ipv4ListExcluded.length; i++) {
        var parts = ipv4ListExcluded[i].split('.');
        expect(isIpv4Parts(parts, inputMode: LeadingZerosMode.excluded), true);
      }
    });

    test('Test isIpv4Parts error', () {
      for (var i = 0; i < ipv4ErrorList.length; i++) {
        var parts = ipv4ErrorList[i].split('.');
        expect(isIpv4Parts(parts, inputMode: LeadingZerosMode.any), false);
        expect(isIpv4Parts(parts, inputMode: LeadingZerosMode.included), false);
        expect(
            isIpv4Parts(parts, inputMode: LeadingZerosMode.includedCompletely),
            false);
        expect(isIpv4Parts(parts, inputMode: LeadingZerosMode.excluded), false);
      }
      expect(
          isIpv4Parts(ipv4ErrorList[2].split('.'),
              inputMode: LeadingZerosMode.any, checkLength: false),
          true);
    });
  });

  group('isIpv4Int and isIpv4BigInt tests', () {
    test('isIpv4Int test', () {
      var isIpv4Int = ipUtils.isIpv4Int;
      expect(isIpv4Int(0), true);
      expect(isIpv4Int(1), true);
      expect(isIpv4Int(255), true);
      expect(isIpv4Int(256), true);
      expect(isIpv4Int(65535), true);
      expect(isIpv4Int(65536), true);
      expect(isIpv4Int(4294967295), true);
      expect(isIpv4Int(IpUtils.ipv4MinInt - 1), false);
      expect(isIpv4Int(IpUtils.ipv4MaxInt + 1), false);
    });
    test('isIpv4BigInt test', () {
      var isIpv4BigInt = ipUtils.isIpv4BigInt;
      expect(isIpv4BigInt(IpUtils.ipv6MinBigInt), true);
      expect(isIpv4BigInt(BigInt.from(1)), true);
      expect(isIpv4BigInt(BigInt.from(255)), true);
      expect(isIpv4BigInt(BigInt.from(256)), true);
      expect(isIpv4BigInt(BigInt.from(65535)), true);
      expect(isIpv4BigInt(BigInt.from(65536)), true);
      expect(isIpv4BigInt(BigInt.from(4294967295)), true);
      expect(isIpv4BigInt(BigInt.from(IpUtils.ipv4MinInt) - BigInt.one), false);
      expect(isIpv4BigInt(BigInt.from(IpUtils.ipv4MaxInt) + BigInt.one), false);
    });
  });

  group('ipv4 mask cidr tests', () {
    test('isIpv4Cidr tests', () {
      var isIpv4Cidr = ipUtils.isIpv4Cidr;

      expect(isIpv4Cidr('32', inputMode: LeadingZerosMode.any), true);
      expect(isIpv4Cidr('32', inputMode: LeadingZerosMode.included), true);
      expect(isIpv4Cidr('32', inputMode: LeadingZerosMode.includedCompletely),
          true);
      expect(isIpv4Cidr('32', inputMode: LeadingZerosMode.excluded), true);

      expect(isIpv4Cidr('02', inputMode: LeadingZerosMode.any), true);
      expect(isIpv4Cidr('02', inputMode: LeadingZerosMode.included), true);
      expect(isIpv4Cidr('02', inputMode: LeadingZerosMode.includedCompletely),
          true);
      expect(isIpv4Cidr('02', inputMode: LeadingZerosMode.excluded), false);

      expect(isIpv4Cidr('2', inputMode: LeadingZerosMode.any), true);
      expect(isIpv4Cidr('2', inputMode: LeadingZerosMode.included), false);
      expect(isIpv4Cidr('2', inputMode: LeadingZerosMode.includedCompletely),
          false);
      expect(isIpv4Cidr('2', inputMode: LeadingZerosMode.excluded), true);

      expect(isIpv4Cidr('33', inputMode: LeadingZerosMode.any), false);
    });

    test('isIpv4CidrInt tests', () {
      var isIpv4CidrInt = ipUtils.isIpv4CidrInt;

      expect(isIpv4CidrInt(IpUtils.ipv4CidrMin), true);
      expect(isIpv4CidrInt(IpUtils.ipv4CidrMax), true);

      expect(isIpv4CidrInt(IpUtils.ipv4CidrMin - 1), false);
      expect(isIpv4CidrInt(IpUtils.ipv4CidrMax + 1), false);
    });
  });

  test('isIpv4Mask tests', () {
    var isIpv4Mask = ipUtils.isIpv4Mask;

    var val = isIpv4Mask('255.255.255.255', inputMode: LeadingZerosMode.any);
    expect(val, true);
    val = isIpv4Mask('255.255.255.255', inputMode: LeadingZerosMode.included);
    expect(val, true);
    val = isIpv4Mask('255.255.255.255',
        inputMode: LeadingZerosMode.includedCompletely);
    expect(val, true);
    val = isIpv4Mask('255.255.255.255', inputMode: LeadingZerosMode.excluded);
    expect(val, true);

    val = isIpv4Mask('192.0.0.0', inputMode: LeadingZerosMode.any);
    expect(val, true);
    val = isIpv4Mask('192.0.0.0', inputMode: LeadingZerosMode.included);
    expect(val, false);
    val =
        isIpv4Mask('192.0.0.0', inputMode: LeadingZerosMode.includedCompletely);
    expect(val, false);
    val = isIpv4Mask('192.0.0.0', inputMode: LeadingZerosMode.excluded);
    expect(val, true);
  });

  test('getIpv4MaskFromCidr and tryGetIpv4MaskFromCidr tests', () {
    var getIpv4MaskFromCidr = ipUtils.ipv4CidrToMask;
    var tryGetIpv4MaskFromCidr = ipUtils.ipv4CidrToMaskDefault;

    String? val = getIpv4MaskFromCidr('0', inputMode: LeadingZerosMode.any);
    expect(val, '0.0.0.0');

    val = tryGetIpv4MaskFromCidr('0', inputMode: LeadingZerosMode.included);
    expect(val, null);
    val = tryGetIpv4MaskFromCidr('0',
        inputMode: LeadingZerosMode.includedCompletely, defaultValue: '');
    expect(val, '');
    val = tryGetIpv4MaskFromCidr('0',
        inputMode: LeadingZerosMode.excluded,
        outputMode: LeadingZerosMode.included);
    expect(val, '00.00.00.00');
    val = tryGetIpv4MaskFromCidr('0',
        inputMode: LeadingZerosMode.excluded,
        outputMode: LeadingZerosMode.includedCompletely);
    expect(val, '000.000.000.000');
  });

  group('ipv4 converting tests', () {
    test('intToIpv4 and ipv4ToInt tests', () {
      var tryIpv4ToInt = ipUtils.ipv4ToIntDefault;
      var tryIntToIpv4 = ipUtils.intToIpv4Default;

      int? val = tryIpv4ToInt('192.168.0.1', inputMode: LeadingZerosMode.any);
      expect(val, 3232235521);
      String? str = tryIntToIpv4(3232235521, outputMode: LeadingZerosMode.any);
      expect(str, '192.168.0.1');

      val = tryIpv4ToInt('192.168.0.1', inputMode: LeadingZerosMode.excluded);
      expect(val, 3232235521);
      str = tryIntToIpv4(3232235521, outputMode: LeadingZerosMode.excluded);
      expect(str, '192.168.0.1');

      val = tryIpv4ToInt('192.168.0.1', inputMode: LeadingZerosMode.included);
      expect(val, null);
      str = tryIntToIpv4(3232235521, outputMode: LeadingZerosMode.included);
      expect(str, '192.168.00.01');

      val = tryIpv4ToInt('192.168.0.1',
          inputMode: LeadingZerosMode.includedCompletely, defaultValue: -1);
      expect(val, -1);
      str = tryIntToIpv4(3232235521,
          outputMode: LeadingZerosMode.includedCompletely);
      expect(str, '192.168.000.001');

      // inputMode is options.ipv4InputIpLeadingZerosMode
      val = tryIpv4ToInt('192.168.1.1');
      expect(val, 3232235777);
      val = tryIpv4ToInt('192.168.1.1', inputMode: LeadingZerosMode.any);
      expect(val, 3232235777);
      val = tryIpv4ToInt('192.168.1.1', inputMode: LeadingZerosMode.excluded);
      expect(val, 3232235777);
      val = tryIpv4ToInt('192.168.1.1', inputMode: LeadingZerosMode.included);
      expect(val, null);
      val = tryIpv4ToInt('192.168.1.1',
          inputMode: LeadingZerosMode.includedCompletely, defaultValue: -1);
      expect(val, -1);

      val = tryIpv4ToInt('192.168.01.01', inputMode: LeadingZerosMode.any);
      expect(val, 3232235777);
      val = tryIpv4ToInt('192.168.01.01', inputMode: LeadingZerosMode.excluded);
      expect(val, null);
      val = tryIpv4ToInt('192.168.01.01', inputMode: LeadingZerosMode.included);
      expect(val, 3232235777);
      val = tryIpv4ToInt('192.168.01.01',
          inputMode: LeadingZerosMode.includedCompletely, defaultValue: -1);
      expect(val, -1);

      val = tryIpv4ToInt('192.168.001.001', inputMode: LeadingZerosMode.any);
      expect(val, 3232235777);
      val =
          tryIpv4ToInt('192.168.001.001', inputMode: LeadingZerosMode.excluded);
      expect(val, null);
      val =
          tryIpv4ToInt('192.168.001.001', inputMode: LeadingZerosMode.included);
      expect(val, 3232235777);
      val = tryIpv4ToInt('192.168.001.001',
          inputMode: LeadingZerosMode.includedCompletely, defaultValue: -1);
      expect(val, 3232235777);

      // Generate and test 1000 IPv4 addresses
      for (int i = 0; i < 1000; i++) {
        String ip = Faker().internet.ipv4Address();
        int? ipInt = tryIpv4ToInt(ip);
        String? ipString = tryIntToIpv4(ipInt!);
        expect(ip == ipString, true,
            reason:
                'Failed for address: ip: $ip  ipString: $ipString  ipInt: $ipInt');
      }
    });
  });

  test('completeEndIpv4 tests', () {
    var tryCompleteEndIpv4 = ipUtils.completeEndIpv4Default;

    // Use ipUtils.options.ipv4InputIpLeadingZerosMode to inputMode. Here is LeadingZerosMode.excluded.
    // And use ipUtils.options.ipv4OutputIpLeadingZerosMode to outputMode. Here is LeadingZerosMode.excluded.
    var val = tryCompleteEndIpv4('192.168.0.1', '10');
    expect(val, '192.168.0.10');

    val = tryCompleteEndIpv4('192.168.0.1', '10',
        inputMode: LeadingZerosMode.any, outputMode: LeadingZerosMode.any);
    expect(val, '192.168.0.10');

    val = tryCompleteEndIpv4('192.168.00.1', '10',
        inputMode: LeadingZerosMode.any, outputMode: LeadingZerosMode.any);
    expect(val, '192.168.00.10');

    val = tryCompleteEndIpv4('192.168.000.1', '10',
        inputMode: LeadingZerosMode.any, outputMode: LeadingZerosMode.any);
    expect(val, '192.168.000.10');

    val = tryCompleteEndIpv4('192.168.0.1', '10',
        inputMode: LeadingZerosMode.any, outputMode: LeadingZerosMode.included);
    expect(val, '192.168.00.010');

    val = tryCompleteEndIpv4('192.168.0.1', '10',
        inputMode: LeadingZerosMode.any,
        outputMode: LeadingZerosMode.includedCompletely);
    expect(val, '192.168.000.010');

    val = tryCompleteEndIpv4('192.168.0.1', '10',
        inputMode: LeadingZerosMode.any, outputMode: LeadingZerosMode.excluded);
    expect(val, '192.168.0.10');

    val = tryCompleteEndIpv4('192.168.0.1', '10',
        inputMode: LeadingZerosMode.included,
        outputMode: LeadingZerosMode.excluded);
    expect(val, null);

    val = tryCompleteEndIpv4('192.168.0.1', '10',
        inputMode: LeadingZerosMode.includedCompletely,
        outputMode: LeadingZerosMode.excluded,
        defaultValue: '');
    expect(val, '');

    val = tryCompleteEndIpv4('192.168.0.1', '10',
        inputMode: LeadingZerosMode.excluded,
        outputMode: LeadingZerosMode.excluded,
        defaultValue: '');
    expect(val, '192.168.0.10');
  });

  test('compareIpv4 tests', () {
    var tryCompareIpv4 = ipUtils.compareIpv4Default;

    int? val = tryCompareIpv4('192.168.0.1', '192.168.0.2',
        inputMode: LeadingZerosMode.any);
    expect(val, -1);
  });

  test('handleIpv4LeadingZeros tests', () {
    var handleIpv4LeadingZeros = ipUtils.handleIpv4Output;

    var val =
        handleIpv4LeadingZeros('192.168.0.1', outputMode: LeadingZerosMode.any);
    expect(val, '192.168.0.1');

    val = handleIpv4LeadingZeros('192.168.0.1',
        outputMode: LeadingZerosMode.included);
    expect(val, '192.168.00.01');

    val = handleIpv4LeadingZeros('192.168.0.1',
        outputMode: LeadingZerosMode.includedCompletely);
    expect(val, '192.168.000.001');

    val = handleIpv4LeadingZeros('192.168.000.01',
        outputMode: LeadingZerosMode.excluded);
    expect(val, '192.168.0.1');
  });

  test('createIpv4ListFromRanges test', () {
    var createIpv4ListFromRanges = ipUtils.createIpv4ListFromRanges;

    var val = createIpv4ListFromRanges('192.168.0.1-192.168.0.10',
        inputMode: LeadingZerosMode.any, outputMode: LeadingZerosMode.any);
    expect(val, [
      '192.168.0.1',
      '192.168.0.2',
      '192.168.0.3',
      '192.168.0.4',
      '192.168.0.5',
      '192.168.0.6',
      '192.168.0.7',
      '192.168.0.8',
      '192.168.0.9',
      '192.168.0.10'
    ]);

    val = createIpv4ListFromRanges('192.168.0.1-192.168.0.2,192.168.0.3-192.168.0.10',
        inputMode: LeadingZerosMode.any, outputMode: LeadingZerosMode.included);
    expect(val, [
      '192.168.00.01',
      '192.168.00.02',
      '192.168.00.03',
      '192.168.00.04',
      '192.168.00.05',
      '192.168.00.06',
      '192.168.00.07',
      '192.168.00.08',
      '192.168.00.09',
      '192.168.00.010'
    ]);
  });
}
